// Copyright (C) joyinter
// All rights reserved.
// 
// Author : Jiang Li
// Date   : 2004-8-26

#include "stdafx.h"
#include "socktool.h"
#include "sockbase.h"
#include "utility.h"
#include "socklistener.h"

//#define ENABLE_RECV_TRACE
//#define ENABLE_UDP_TRACE 

static const int RECV_BUF_SIZE = 1024*16;
static const int RECV_BLOCK_MAX = 1024*128;

#pragma warning(disable : 4073)
#pragma init_seg(lib)
CJoySocketTool  g_sockTool;

//##ModelId=44C4B5F50312
CJoySocketTool::CJoySocketTool()
{
    m_shutdown  = false;
    m_timeOut   = 200;
    m_hAsyWnd   = NULL;

    CreateAsyWindow();
    CreateClearThread();
}

//##ModelId=44C4B5F5031C
CJoySocketTool::~CJoySocketTool()
{
    m_shutdown = true;
    
    CloseClearThread();
    DestroyAsyWindow();
}

//##ModelId=44C4B5F5038A
bool CJoySocketTool::CreateAsyWindow()
{
    static char* wndClsName = "JoySockAsyWindowClass";
    WNDCLASS wc;
    wc.style        = 0;
    wc.lpfnWndProc  = sAsyWindowProc;
    wc.cbClsExtra   = 0;
    wc.cbWndExtra   = 0;
    wc.hInstance    = GetModuleHandle(NULL);
    wc.hIcon        = NULL;
    wc.hCursor      = NULL;
    wc.hbrBackground= (HBRUSH)COLOR_WINDOW;
    wc.lpszMenuName = NULL;
    wc.lpszClassName= wndClsName;

    RegisterClass(&wc);

    m_hAsyWnd = CreateWindow(wndClsName, NULL, 0, 0, 0, 10, 10, NULL, NULL, wc.hInstance, NULL);

    if(m_hAsyWnd == NULL)
    {
        MessageBox(NULL, "Cannot create asy window.", "Error", MB_OK);
        return false;
    }

    return true;
}

//##ModelId=44C4B5F50399
void CJoySocketTool::DestroyAsyWindow()
{
    if(m_hAsyWnd != NULL)
    {
        DestroyWindow(m_hAsyWnd);
        m_hAsyWnd = NULL;
    }
}

//##ModelId=44C4B5F503A9
LRESULT CJoySocketTool::AsyWindowProc(HWND hWnd, UINT nMessage, WPARAM wParam, LPARAM lParam)
{
    switch(nMessage)
    {
    case SAM_RECV_DATA:
        {
            CJoySockRecvData* pData = PeekRecvData();
            while(pData != NULL)
            {
#ifdef ENABLE_UDP_TRACE
                if(pData->m_from.sin_family)
                {
                    static int ccc = 0;
                    TRACE("Process RecvFrom Begin %d\n", ++ccc);
                }
#endif
                CJoySockRecvData* pTemp = pData;
                pData = pData->m_next;

                CJoySockData* sockData = pTemp->m_sockData;
                CJoySockBase* sock = const_cast<CJoySockBase*>(sockData->m_owner);
                if(sock != NULL)
                {
                    sock->OnRecvData(*pTemp);
                }
                delete pTemp;
            }
        }
        return 0;
    case SAM_CONNECTED:
        {
            CJoySockData* sockData = (CJoySockData*)wParam;
            int e = (int)lParam;
            if(sockData->m_owner != NULL)
            {
                const_cast<CJoySockBase*>(sockData->m_owner)->OnConnect(e);
            }
            sockData->Release();
        }
        return 0;
    case SAM_CLOSE_SOCK:
        {
            CJoySockData* sockData = (CJoySockData*)wParam;
            if(sockData->m_owner != NULL)
            {
                const_cast<CJoySockBase*>(sockData->m_owner)->Close();
            }
            sockData->Release();
        }
        return 0;
    case SAM_ACCEPT:
        {
            //CJoySockData* sockData  = (CJoySockData*)wParam;
            //CJoySockAccept* accData = (CJoySockAccept*)lParam;
            //CJoySockData* sockDataA = accData->m_data;
            //CJoySockBase* pSock = const_cast<CJoySockBase*>(sockData->m_owner);
            //if(pSock != NULL)
            //{
            //    ((CJoySockListener*)pSock)->OnAccept(
            //        sockDataA, accData->m_callerData, accData->m_callerDataSize);
            //}
            //delete accData;
            //sockDataA->Release();
            //sockData->Release();

            CJoySockData* sockData = (CJoySockData*)wParam;
            CJoySockData* sockDataA = (CJoySockData*)lParam;
            CJoySockBase* pSock = const_cast<CJoySockBase*>(sockData->m_owner);
            if(pSock != NULL)
            {
                ((CJoySockListener*)pSock)->OnAccept(sockDataA);
            }
            sockDataA->Release();
            sockData->Release();
        }
        return 0;
    }
    return DefWindowProc(hWnd, nMessage, wParam, lParam);
}

//##ModelId=44C4B5F503C8
LRESULT CALLBACK CJoySocketTool::sAsyWindowProc(HWND hWnd, UINT nMessage, WPARAM wParam, LPARAM lParam)
{
    return g_sockTool.AsyWindowProc(hWnd, nMessage, wParam, lParam);
}

//##ModelId=44C4B5F5037A
HANDLE CJoySocketTool::CreateThread(LPTHREAD_START_ROUTINE pfnThreadProc, void* pContext, bool bSuspend)
{
    DWORD dwThreadId;
    HANDLE hThread = ::CreateThread(
        NULL,
        128*1024, //0, // stack size.
        pfnThreadProc,
        pContext,
        bSuspend ? CREATE_SUSPENDED : 0,
        &dwThreadId);

    if(hThread == NULL)
    {
        SYSTEMTIME st;
        GetLocalTime(&st);
        TRACE("[%.4d-%.2d-%.2d %.2d:%.2d:%.2d] Create thread failed<%d>.\n",
            st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, GetLastError());
        return NULL;
    }

    return hThread;
}

//##ModelId=44C4B5F60119
int CJoySocketTool::CClearThread::PeekThreads(HANDLE* pHandle, int c)
{
    CJoyAutoCS gate(m_lock);
    int r = 0;
    while(!m_threads.IsEmpty() && r < c)
    {
        *pHandle = m_threads.RemoveHead();
        ++ pHandle;
        ++ r;
    }
    if(r == 0)
    {
        ResetEvent(m_hEvent);
    }
    return r;
}

//##ModelId=44C4B5F5036B
void CJoySocketTool::AddClearThread(HANDLE hThread)
{
    if(m_clearThread.m_hThread == NULL)
    {
        return;
    }
    CJoyAutoCS gate(m_clearThread.m_lock);
    if(m_clearThread.m_threads.IsEmpty())
    {
        SetEvent(m_clearThread.m_hEvent);
    }
    m_clearThread.m_threads.AddTail(hThread);
}

//##ModelId=44C4B5F5033C
DWORD CJoySocketTool::sClearThreadProc(void* pContext)
{
    return g_sockTool.ClearThreadProc(pContext);
}

//##ModelId=44C4B5F5032C
DWORD CJoySocketTool::ClearThreadProc(void*)
{
    const nCount = 64;
    for(;;)
    {
        HANDLE threads[nCount];
        int c = m_clearThread.PeekThreads(threads, nCount);
        if(c > 0)
        {
            if(WAIT_TIMEOUT == WaitForMultipleObjects(c, threads, TRUE, m_clearThread.m_dwWaitTime))
            {
                for(int i = 0; i < c; ++ i)
                {
                    //??
                    //TerminateThread(threads[i], 0);
                }
            }
            for(int i = 0; i < c; ++ i)
            {
                CloseHandle(threads[i]);
            }
        }
        else
        {
            if(m_shutdown)
            {
                break;
            }
            WaitForSingleObject(m_clearThread.m_hEvent, INFINITE);
        }
    }
    return 0;
}

//##ModelId=44C4B5F5034B
bool CJoySocketTool::CreateClearThread()
{
    m_clearThread.m_dwWaitTime = m_timeOut*4;

    m_clearThread.m_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    ASSERT(m_clearThread.m_hEvent != NULL);

    m_clearThread.m_hThread = CreateThread(sClearThreadProc, NULL);
    ASSERT(m_clearThread.m_hThread != NULL);

    return true;
}

//##ModelId=44C4B5F5035B
void CJoySocketTool::CloseClearThread()
{
    m_clearThread.m_lock.Lock();
    SetEvent(m_clearThread.m_hEvent);
    m_clearThread.m_lock.Unlock();

    if(m_clearThread.m_hThread != NULL)
    {
        if(WAIT_TIMEOUT == WaitForSingleObject(m_clearThread.m_hThread, m_clearThread.m_dwWaitTime*2))
        {
            TRACE("Clear thread timeout.\n");
            TerminateThread(m_clearThread.m_hThread, 0);
        }
        CloseHandle(m_clearThread.m_hThread);
        m_clearThread.m_hThread = NULL;
    }

    CloseHandle(m_clearThread.m_hEvent);
    m_clearThread.m_hEvent = NULL;
}

static bool ShouldSend(CJoySockData* pData)
{
    if(pData->m_bClose)
    {
        if(pData->m_bCancelSend)
        {
            return false;
        }
    }
    return !g_sockTool.m_shutdown;
}

static bool ShouldRecv(CJoySockData* pData)
{
    if(pData->m_bClose)
    {
        return false;
    }
    return !g_sockTool.m_shutdown;
}

// thread procedures.

//##ModelId=44C4B5F6001F
DWORD WINAPI CJoySocketTool::sConnectThreadProc(void* pContext)
{
    return g_sockTool.ConnectThreadProc(pContext);
}

//##ModelId=44C4B5F60012
DWORD CJoySocketTool::ConnectThreadProc(void* pContext)
{
    CJoySockConnect* connData = (CJoySockConnect*)pContext;
    CJoySockData* sockData = connData->m_data;
    sockaddr_in addr    = connData->m_addr;

    int e = 0;
    //if(SOCKET_ERROR == WSAConnect(sockData->m_hSocket,
    //    (sockaddr*)&addr, sizeof(addr), pCallerBuf, pCallerBuf, NULL, NULL))
    if(SOCKET_ERROR == connect(sockData->m_hSocket, (sockaddr*)&addr, sizeof(addr)))
    {
        e = WSAGetLastError();
    }
    else
    {
        sockData->m_bConnected = true;
    }

    delete connData;
    PostAsyMessage(SAM_CONNECTED, (WPARAM)sockData, e);

    // release sockData in asywindow proc.
    // sockData->Release();
    return 0;
}

//##ModelId=44C4B5F60050
DWORD CJoySocketTool::sSendThreadProc(void*pContext)
{
    return g_sockTool.SendThreadProc(pContext);
}

//##ModelId=44C4B5F6005D
DWORD CJoySocketTool::sSendBlockThreadProc(void*pContext)
{
    return g_sockTool.SendBlockThreadProc(pContext);
}

//##ModelId=44C4B5F6006D
DWORD CJoySocketTool::sSendToThreadProc(void*pContext)
{
    return g_sockTool.SendToThreadProc(pContext);
}

//##ModelId=44C4B5F60033
DWORD CJoySocketTool::SendThreadProc(void* pContext)
{
    CJoySockData* sockData = (CJoySockData*)pContext;
    SOCKET s = sockData->m_hSocket;
    bool bBreak = false;
    while(!bBreak)
    {
        if(!ShouldSend(sockData))
        {
            break;
        }
        CJoySockData::CSendItem* pItem = sockData->PeekSendItem();
        if(pItem == NULL)
        {
            if(sockData->m_bClose)
            {
                break;
            }
            else
            {
                WaitForSingleObject(sockData->m_hSendEvent, INFINITE);
            }
            continue;
        }
        while(pItem != NULL && !bBreak)
        {
            char* buf = (char*)pItem->m_data->GetData();
            int len = pItem->m_data->GetDataSize();
            int sent = 0;
            while(sent < len)
            {
                if(!ShouldSend(sockData))
                {
                    bBreak = true;
                    break;
                }

                int r = send(s, buf+sent, len-sent, 0);
                if(r >= 0)
                {
                    sent += r;
                    continue;
                }

                int e = WSAGetLastError();
                switch(e)
                {
                case WSAETIMEDOUT:
                    continue;

                case WSAEWOULDBLOCK:
                    {
                        int c = 0;
                        do
                        {
					        fd_set fd;
					        FD_ZERO(&fd);
					        FD_SET(s,&fd);
					        timeval tv;
					        tv.tv_sec=0;
                            tv.tv_usec = this->m_timeOut;
                            c = select(0,NULL,&fd,NULL,&tv);
                        }
                        while(ShouldSend(sockData) && 0 == c);
                    }
                    continue;
                default:
                    sockData->PostClose();
                }
                bBreak = true;
                break;
            }
            CJoySockData::CSendItem* pTemp = pItem;
            pItem = pItem->m_next;
            delete pTemp;
        }
        while(pItem != NULL)
        {
            CJoySockData::CSendItem* pTemp = pItem;
            pItem = pItem->m_next;
            delete pTemp;
        }
    }

    sockData->Release();
    return 0;
}
//changed by dengxinguo 0518
//##ModelId=44C4B5F600AB
DWORD CJoySocketTool::RecvThreadProc(void* pContext)
{
    CJoySockData* sockData = (CJoySockData*)pContext;
    char buf[RECV_BUF_SIZE];

    while(ShouldRecv(sockData))
    {
        int nSize = 0;

        nSize = recv(sockData->m_hSocket, buf, sizeof(buf), 0);


        if(nSize > 0)
        {
#ifdef ENABLE_UDP_TRACE
            static int ccc = 0;
            TRACE("Recv Begin %d\n", ++ccc);
#endif
            CJoySockRecvData* pData = CJoySockRecvData::Create(sockData, buf, nSize);
            sockData->PostRecvData(pData);

#ifdef ENABLE_UDP_TRACE
            TRACE("Recv End %d\n", ccc);
#endif
            continue;
        }
		int e = WSAGetLastError();     
		if(nSize == 0)
        {
		/*	char szLog1[200];
			sprintf(szLog1,"test2 nSize == 0,socket close WSAGetLastError()=%d ",e);
			g_sockTool.DbPrint(szLog1);*/
            sockData->PostClose();
            sockData->Release();
            return 0;
        }
		  
        switch(e)
        {
		case WSAECONNRESET:
		case WSAENETRESET:
		case WSAENOTCONN:
		case WSAENOTSOCK:
		/*	char szLog[200];
			sprintf(szLog,"socket close WSAGetLastError()=%d ",e);
			g_sockTool.DbPrint(szLog);*/
            sockData->PostClose();
            sockData->Release();
            return 0;
	
           
        default:
			continue;
        }
    }

    sockData->Release();
    return 0;
}
//DWORD CJoySocketTool::RecvThreadProc(void* pContext)
//{
//    CJoySockData* sockData = (CJoySockData*)pContext;
//    char buf[RECV_BUF_SIZE];
//
//    while(ShouldRecv(sockData))
//    {
//        int nSize = 0;
//
//        nSize = recv(sockData->m_hSocket, buf, sizeof(buf), 0);
//
//
//        if(nSize > 0)
//        {
//#ifdef ENABLE_UDP_TRACE
//            static int ccc = 0;
//            TRACE("Recv Begin %d\n", ++ccc);
//#endif
//            CJoySockRecvData* pData = CJoySockRecvData::Create(sockData, buf, nSize);
//            sockData->PostRecvData(pData);
//
//#ifdef ENABLE_UDP_TRACE
//            TRACE("Recv End %d\n", ccc);
//#endif
//            continue;
//        }
//		int e = WSAGetLastError();
//        if(nSize == 0)
//        {
//			char szLog1[200];
//			sprintf(szLog1,"test2 nSize == 0,socket close WSAGetLastError()=%d ",e);
//			g_sockTool.DbPrint(szLog1);
//            sockData->PostClose();
//            sockData->Release();
//            return 0;
//        }
//       
//        switch(e)
//        {
//		case 0:
//        case WSAEWOULDBLOCK:
//        case WSAETIMEDOUT:
//            continue;
//        default:
//			char szLog[200];
//			sprintf(szLog,"socket close WSAGetLastError()=%d ",e);
//			g_sockTool.DbPrint(szLog);
//            sockData->PostClose();
//            sockData->Release();
//            return 0;
//        }
//    }
//
//    sockData->Release();
//    return 0;
//}

//##ModelId=44C4B5F6003F
DWORD CJoySocketTool::SendBlockThreadProc(void* pContext)
{
    CJoySockData* sockData = (CJoySockData*)pContext;
    SOCKET s = sockData->m_hSocket;
    bool bBreak = false;
    while(!bBreak)
    {
        if(!ShouldSend(sockData))
        {
            break;
        }
        CJoySockData::CSendItem* pItem = sockData->PeekSendItem();
        if(pItem == NULL)
        {
            if(sockData->m_bClose)
            {
                break;
            }
            else
            {
                WaitForSingleObject(sockData->m_hSendEvent, INFINITE);
            }
            continue;
        }
        while(pItem != NULL && !bBreak)
        {
            CJoyAutoCS gate(sockData->m_sendingLock);

#ifdef ENABLE_RECV_TRACE
            TRACE("TCP SendBlock begin.\n");
#endif
            char* buf = (char*)pItem->m_data->GetBlock();
            int len = pItem->m_data->GetBlockSize();
            int sent = 0;
            while(sent < len)
            {
                if(!ShouldSend(sockData))
                {
                    bBreak = true;
                    break;
                }

                int r = send(s, buf+sent, len-sent, 0);
                if(r >= 0)
                {
                    sent += r;
                    continue;
                }

                int e = WSAGetLastError();
                switch(e)
                {
                case WSAETIMEDOUT:
                    continue;

                case WSAEWOULDBLOCK:
                    {
                        int c = 0;
                        do
                        {
					        fd_set fd;
					        FD_ZERO(&fd);
					        FD_SET(s,&fd);
					        timeval tv;
					        tv.tv_sec=0;
                            tv.tv_usec = this->m_timeOut;
                            c = select(0,NULL,&fd,NULL,&tv);
                        }
                        while(ShouldSend(sockData) && 0 == c);
                    }
                    continue;
                default:
                    sockData->PostClose();
                }
                bBreak = true;
                break;
            }
            CJoySockData::CSendItem* pTemp = pItem;
            pItem = pItem->m_next;
            delete pTemp;
#ifdef ENABLE_RECV_TRACE
            TRACE("TCP SendBlock end.\n");
#endif
        }
        while(pItem != NULL)
        {
            CJoySockData::CSendItem* pTemp = pItem;
            pItem = pItem->m_next;
            delete pTemp;
        }
    }

    sockData->Release();
    return 0;
}
static bool RecvData(CJoySockData* sockData, void* buf, int nSize)
{
    char* b = (char*)buf;
    int nRecv = 0;
    while(nRecv < nSize)
    {
        if(!ShouldRecv(sockData))
        {
            return false;
        }
        int r = recv(sockData->m_hSocket, b+nRecv, nSize-nRecv, 0);
        if(r > 0)
        {
            nRecv += r;
            continue;
        }

		int e = WSAGetLastError();
        if(r == 0)
        {
		/*	char szLog1[200];
			sprintf(szLog1,"test1 nSize == 0,socket closes  WSAGetLastError()=%d ",e);
			g_sockTool.DbPrint(szLog1);*/
            sockData->PostClose();
            return false;
        }
		      
        switch(e)
        {
			case WSAECONNRESET:
			case WSAENETRESET:
			case WSAENOTCONN:
			case WSAENOTSOCK:
			/*char szLog[200];
			sprintf(szLog,"socket close WSAGetLastError()=%d ",e);
			g_sockTool.DbPrint(szLog);*/
            sockData->PostClose();
            return false;
	
           
			 default:
				continue;
      
        }
    }
    return true;
}
//static bool RecvData(CJoySockData* sockData, void* buf, int nSize)
//{
//    char* b = (char*)buf;
//    int nRecv = 0;
//    while(nRecv < nSize)
//    {
//        if(!ShouldRecv(sockData))
//        {
//            return false;
//        }
//        int r = recv(sockData->m_hSocket, b+nRecv, nSize-nRecv, 0);
//        if(r > 0)
//        {
//            nRecv += r;
//            continue;
//        }
//		int e = WSAGetLastError();
//        if(r == 0)
//        {
//			char szLog1[200];
//			sprintf(szLog1,"test1 nSize == 0,socket closes  WSAGetLastError()=%d ",e);
//			g_sockTool.DbPrint(szLog1);
//            sockData->PostClose();
//            return false;
//        }
//       
//        switch(e)
//        {
//        case WSAEWOULDBLOCK:
//        case WSAETIMEDOUT:
//            continue;
//        default:
//			char szLog[200];
//			sprintf(szLog,"socket close WSAGetLastError()=%d ",e);
//			g_sockTool.DbPrint(szLog);
//            sockData->PostClose();
//            return false;
//        }
//    }
//    return true;
//}

//##ModelId=44C4B5F600AD
DWORD CJoySocketTool::RecvBlockThreadProc(void* pContext)
{
    CJoySockData* sockData = (CJoySockData*)pContext;

    while(ShouldRecv(sockData))
    {
        int nSize = 0;
        if(!RecvData(sockData, &nSize, sizeof(nSize)))
        {
            break;
        }
        if(nSize > RECV_BLOCK_MAX)
        {
            sockData->PostClose();
            break;
        }
        CJoySockRecvData* pData = CJoySockRecvData::Create(sockData, nSize);
        if(!RecvData(sockData, pData->GetData(), nSize))
        {
            delete pData;
            break;
        }
        pData->m_from.sin_family = 0;
        sockData->PostRecvData(pData);
    }

    sockData->Release();
    return 0;
}

//##ModelId=44C4B5F6004E
DWORD CJoySocketTool::SendToThreadProc(void*pContext)
{
    CJoySockData* sockData = (CJoySockData*)pContext;
    SOCKET s = sockData->m_hSocket;

    while(ShouldSend(sockData))
    {
        CJoySockData::CSendItem* pItem = sockData->PeekSendItem();
        if(pItem == NULL)
        {
            if(sockData->m_bClose)
            {
                break;
            }
            else
            {
                WaitForSingleObject(sockData->m_hSendEvent, INFINITE);
            }
            continue;
        }
        while(pItem != NULL && ShouldSend(sockData))
        {
            char* buf = (char*)pItem->m_data->GetData();
            int len = pItem->m_data->GetDataSize();

#ifdef ENABLE_UDP_TRACE
            static int ccc = 0;
            TRACE("SendTo Begin %d\n", ++ccc);
#endif
            int r = sendto(s, buf, len, 0, (sockaddr*)&pItem->m_addr, sizeof(pItem->m_addr));
            if(r == SOCKET_ERROR)
            {
                int e = WSAGetLastError();
                switch(e)
                {
                case WSAETIMEDOUT:
                    break;

                case WSAEWOULDBLOCK:
                    {
                        int c = 0;
                        do
                        {
					        fd_set fd;
					        FD_ZERO(&fd);
					        FD_SET(s,&fd);
					        timeval tv;
					        tv.tv_sec=0;
                            tv.tv_usec = this->m_timeOut;
                            c = select(0,NULL,&fd,NULL,&tv);
                        }
                        while(ShouldSend(sockData) && 0 == c);
                    }
                    break;
                default:
                    //sockData->PostClose();
                    break;
                }
            }
#if 0
            else
            {
                CHAR addrStr[32];
                sprintf(addrStr, "SendTo %d.%d.%d.%d:%d succeeded.",
                    pItem->m_addr.sin_addr.S_un.S_un_b.s_b1,
                    pItem->m_addr.sin_addr.S_un.S_un_b.s_b2,
                    pItem->m_addr.sin_addr.S_un.S_un_b.s_b3,
                    pItem->m_addr.sin_addr.S_un.S_un_b.s_b4,
                    pItem->m_addr.sin_port);
                MessageBox(NULL, addrStr, "", MB_OK);
            }
#endif
            //ASSERT(r == len);

#ifdef ENABLE_UDP_TRACE
            TRACE("SendTo end %d\n", ccc);
#endif

            CJoySockData::CSendItem* pTemp = pItem;
            pItem = pItem->m_next;
            delete pTemp;
        }
        while(pItem != NULL)
        {
            CJoySockData::CSendItem* pTemp = pItem;
            pItem = pItem->m_next;
            delete pTemp;
        }
    }

    sockData->Release();
    return 0;
}

//##ModelId=44C4B5F600BB
DWORD CJoySocketTool::RecvFromThreadProc(void*pContext)
{
    CJoySockData* sockData = (CJoySockData*)pContext;
    char buf[RECV_BUF_SIZE];

    while(ShouldRecv(sockData))
    {
        sockaddr_in addr;
        int addrLen = sizeof(addr);
        int nSize = 0;

        nSize = recvfrom(sockData->m_hSocket, buf, sizeof(buf), 0, (sockaddr*)&addr, &addrLen);


        if(nSize > 0)
        {
#ifdef ENABLE_UDP_TRACE
        static int ccc = 0;
        TRACE("RecvFrom Begin %d\n", ++ccc);
#endif
            CJoySockRecvData* pData = CJoySockRecvData::Create(sockData, buf, nSize);
            pData->m_from = addr;
            sockData->PostRecvData(pData);

#ifdef ENABLE_UDP_TRACE
        TRACE("RecvFrom End %d\n", ccc);
#endif
        }
    }

    sockData->Release();
    return 0;
}

//##ModelId=44C4B5F600BD
DWORD WINAPI CJoySocketTool::sRecvThreadProc(void* pContext)
{
    return g_sockTool.RecvThreadProc(pContext);
}

//##ModelId=44C4B5F600C0
DWORD WINAPI CJoySocketTool::sRecvBlockThreadProc(void* pContext)
{
    return g_sockTool.RecvBlockThreadProc(pContext);
}

//##ModelId=44C4B5F600CD
DWORD WINAPI CJoySocketTool::sRecvFromThreadProc(void* pContext)
{
    return g_sockTool.RecvFromThreadProc(pContext);
}


//##ModelId=44C4B5F6009E
void CJoySocketTool::PostRecvData(CJoySockRecvData* pData)
{
#if 1
    m_recvLock.Lock();

    bool b = m_recvDatas.IsEmpty();
    m_recvDatas.AddTail(pData);

    m_recvLock.Unlock();

    if(b)
    {
        SendAsyMessage(SAM_RECV_DATA, 0, 0);
    }
#else
    CJoyAutoCS gate(m_recvLock);

    if(m_recvDatas.IsEmpty())
    {
        PostAsyMessage(SAM_RECV_DATA, 0, 0);
    }
    m_recvDatas.AddTail(pData);
#endif
}

//##ModelId=44C4B5F600A0
CJoySockRecvData* CJoySocketTool::PeekRecvData()
{
    CJoyAutoCS gate(m_recvLock);

    CJoySockRecvData* pData = m_recvDatas.PeekAll();

    return pData;
}
//##ModelId=44C4B5F60092
void CJoySocketTool::JoySaveLog(const char* path, const char* logText)
{
    if(path == NULL || logText == NULL)
    {
        return;
    }
  
    SYSTEMTIME t;
    GetLocalTime(&t);    

	FILE* f = fopen(path, "a");
    if(f == NULL)
    {
      return;
    }
    if(f != NULL)
    {
        fprintf(f, "[%.4d-%.2d-%.2d %.2d:%.2d:%.2d]",
            t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond);
	    fprintf(f, logText);
		fprintf(f, "\n");
	    fclose(f);
    }
}
//##ModelId=44C4B5F6009C
void CJoySocketTool::DbPrint(const char* logText)
{
	JoySaveLog("e:\\log\\CJoyTCPTransfer.txt",logText);
}
